﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FinPlusCommon;
using System.ComponentModel;
using log = Logger.Logger;
using u = FinPlusUtility.Utility;

namespace FinPlusComponents
{
    public class FinPlusQuoteConnection: FinPlusComponent
    {
        public override string Id { get; set; }
        public override string[] States { get { return new string[] { }; } }
        public override string[] TestStates { get { return new string[] { "IsValid" }; } }
        public override IFinPlusFunctions Model { get { return null; } }
        public override string ModelTest { get { return null; } }
        public override bool IsValid { get; set; }

        private enum DockControls { FinPlusDataConn, FinPlusChildService, FinPlusMessaging, Default }
        private enum Connection { QuoteSource, Exception }
        private enum Params { QuoteSource, ReceiveAction, PublishAction, Size, FunctionName }
        
        private FinPlusMessaging _quotesMessaging;
        private IFinPlusComponent _quoteAdaptorConn;
        private IFinPlusFunction _quoteAdaptor;
        private readonly string _sourceName;
        private const int _quoteExecutePublishPercent = 5, _quoteExecutePercent = 90;

        //construct
        public FinPlusQuoteConnection(string name) 
        {
            _sourceName = name;
            IsValid = true;
        }

        //common control interface
        public override void Dock(object component, string dock)
        {
            try
            {
                switch (u.EnumTryParse<DockControls>(component.GetType().Name, DockControls.Default))
                {
                    case DockControls.FinPlusMessaging: AddFinPlusMessaging((FinPlusMessaging)component); break;
                    case DockControls.FinPlusChildService:
                    case DockControls.FinPlusDataConn:
                    case DockControls.Default: AddConnection((IFinPlusComponent)component, dock); break;
                }
            }
            catch (Exception e)
            {
                IsValid = log.Log(Logger.Level.Error, Id, Config, e.Message, e);
            }
        }

        public override void Initialise()
        {

        }

        public override void CommandRouter(IFinPlusFunction func)
        {
            try
            {
                CaptureCommand(func);

                switch ((Commands)Enum.Parse(typeof(Commands), func.Name, true))
                {
                    case Commands.Quote: Quote(func); break;
                    case Commands.QuoteCancel: QuoteCancel(func); break;
                    case Commands.QuoteExecute: QuoteExecute(func); break;
                    case Commands.QuoteAccept: QuoteAccept(func); break;
                    case Commands.QuoteDecline: QuoteDecline(func); break;
                    case Commands.QuotePublish: QuotePublish(func); break;
                    case Commands.QuoteExecutePublish: QuoteExecutePublish(func); break;
                    case Commands.QuoteCancelPublish: QuoteCancelPublish(func); break;
                    case Commands.QuoteDeclinePublish: QuoteDeclinePublish(func); break;
                    case Commands.QuoteAcceptPublish: QuoteAcceptPublish(func); break;
                    default: throw new Exception(string.Format("event not recognised {0}", func.Name));
                }
            }
            catch (Exception e)
            {
                IsValid = log.Log(Logger.Level.Error, Id, Config, e.Message, e);
            }
        }

        public override void Dispose()
        {
            try
            {
                if (_quoteAdaptorConn != null)
                    _quoteAdaptorConn.Dispose();
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Warning, e.Message, e);
            }
        }

        //private
        private void AddConnection(IFinPlusComponent conn, string dock)
        {
            switch (u.EnumTryParse<Connection>(dock, Connection.Exception))
            {
                case Connection.QuoteSource: AddFinPlusQuoteSource(conn); break;
                case Connection.Exception: throw new NotImplementedException();
            }
        }

        private void AddFinPlusQuoteSource(IFinPlusComponent conn)
        {
            try
            {
                _quoteAdaptorConn = conn;
                _quoteAdaptor = conn.Model.Values.Where(f => f[Params.QuoteSource.ToString()].ToString().Equals(_sourceName)).First<IFinPlusFunction>();
                _quoteAdaptor.Get(Params.PublishAction.ToString(), Publish_Update);
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Error, Id, Config, e.Message, e);
            }
        }

        private void AddFinPlusMessaging(FinPlusMessaging messaging)
        {
            try
            {
                _quotesMessaging = messaging;
                _quotesMessaging.OnUpdate += Message_Update;
            }
            catch (Exception e)
            {
                log.Log(Logger.Level.Error, Id, Config, e.Message, e);
            }
        }

        //quote
        private bool Quote(IFinPlusFunction func)
        {
            //vendor quote
            _quoteAdaptor.Get(Params.ReceiveAction.ToString()).Set(func);
            return true;
        }

        private bool QuoteCancel(IFinPlusFunction func)
        {
            //vendor cancels
            _quoteAdaptor.Get(Params.ReceiveAction.ToString()).Set(func);
            return true;
        }

        private bool QuoteExecute(IFinPlusFunction func)
        {
            //trader trys to execute 
            if (new Random().Next(0, 100) < _quoteExecutePercent)
            {
                //route as accept
                func.Get(Params.FunctionName.ToString()).Value = func.Name = Commands.QuoteAccept.ToString();
                Message_Update(this, func);
            }
            else
            {
                //route as decline
                func.Get(Params.FunctionName.ToString()).Value = func.Name = Commands.QuoteDecline.ToString();
                Message_Update(this, func);
            }
            return true;
        }

        private bool QuoteAccept(IFinPlusFunction func)
        {
            _quoteAdaptor.Get(Params.ReceiveAction.ToString()).Set(func);
            return true;
        }

        private bool QuoteDecline(IFinPlusFunction func)
        {
            _quoteAdaptor.Get(Params.ReceiveAction.ToString()).Set(func);
            return true;
        }

        private bool QuotePublish(IFinPlusFunction func)
        {
            if ((double)func.Value(Params.Size.ToString()) != 0 && new Random().Next(0, 100) < _quoteExecutePublishPercent)
            {
                func.Get(Params.FunctionName.ToString()).Value = func.Name = Commands.QuoteExecutePublish.ToString();
                Message_Update(this, func);
            }

            return true;
        }

        private bool QuoteCancelPublish(IFinPlusFunction func)
        {
            //TODO
            return true;
        }

        private bool QuoteAcceptPublish(IFinPlusFunction func)
        {
            //TODO
            return true;
        }

        private bool QuoteDeclinePublish(IFinPlusFunction func)
        {
            //TODO
            return true;
        }

        private bool QuoteExecutePublish(IFinPlusFunction func)
        {
            _quoteAdaptor.Get(Params.ReceiveAction.ToString()).Set(func);
            return true;
        }

        //cmds
        private new enum Commands { Quote, QuoteCancel, QuoteExecute, QuoteAccept, QuoteDecline, QuotePublish, QuoteDeclinePublish, QuoteCancelPublish, QuoteAcceptPublish, QuoteExecutePublish };

        //events
        private void Message_Update(object sender, IFinPlusFunction func) { CommandRouter(func); }
        private void Publish_Update(object sender, PropertyChangedEventArgs a) { CommandRouter((Function)((IFinPlusItem)sender).Object); }
    }
}
